package net.imagine.core.engine;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import net.imagine.core.ImageOperations;
import net.imagine.core.ImageProcessResult;
import net.imagine.core.ImageProcessService;
import net.imagine.core.ImageProcessTask;
import net.imagine.core.ImageProcessTemplate;
import net.imagine.core.ResultState;
import net.imagine.core.resize.ImageResizeTemplate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
 * <pre>
 * ImageEngine是imagine的入口，所有图片处理都需要调用{@link #processImage(String, List)}方法
 * 系统使用多线程方式运行处理任务队列，用户只需要指定运行总的超时时间，线程池的大小，以及用于处理的算法实现
 * 系统可以与Spring集成，用户只需要配置如下：
 * &lt;bean id=&quot;imageEngine&quot; class=&quot;net.imagine.core.engine.ImageEngine&quot; init-method=&quot;initEngine&quot;&gt;
 *  &lt;property name=&quot;poolSize&quot; value=&quot;3&quot; /&gt;&lt;!-- 线程的线程数，默认处理器数+1 --&gt;
 *  &lt;property name=&quot;timeout&quot; value=&quot;60000&quot; /&gt;&lt;!-- 线程执行超时总时间（单位：ms），默认60000 --&gt;
 *  &lt;property name=&quot;template&quot; ref=&quot;resize&quot; /&gt;&lt;!-- 图片压缩模板实现类 --&gt;
 *  &lt;property name=&quot;useMultiThreadMinSize&quot; value=&quot;2&quot; /&gt;&lt;!-- 使用单线程处理的最大任务数，默认处理器数 --&gt;
 * &lt;/bean&gt;
 * 
 * 用户可以根据自己需要实现 {@link ImageOperations} 接口用于实现图片的操作算法
 * 实现 {@link ImageProcessTemplate#processImage(String, ImageProcessTask)} 来实现自己的图片处理的业务逻辑
 * 可以扩展并实现 {@link ImageProcessTask} 接口来定义自己的图片操作任务
 * 可以扩展 {@link ImageProcessResult}来自定义自己的图片处理结果
 * 
 * 对于图片压缩，系统提供了一种逻辑，用户只需要实现 {@link ImageResizeTemplate} 就可以进行图片压缩了
 * （使用前请先安装GraphicsMagick，并加入im4java依赖包）
 * 具体的Spring配置可以参考文件net.iamgine.config.applicationContext.xml
 * </pre>
 * 
 */
@Component("imageEngine")
public class ImageEngine {
	private static final Log logger = LogFactory.getLog(ImageEngine.class);
	private ImageProcessService service;
	protected ImageProcessTemplate template;
	protected long timeout = 60000;
	protected int poolSize = Runtime.getRuntime().availableProcessors() + 1;
	private int useMultiThreadMinSize = Runtime.getRuntime().availableProcessors();

	public void setTemplate(ImageProcessTemplate template) {
		this.template = template;
	}

	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}

	public void setPoolSize(int poolSize) {
		this.poolSize = poolSize;
	}

	public void setUseMultiThreadMinSize(int useMultiThreadMinSize) {
		this.useMultiThreadMinSize = useMultiThreadMinSize;
	}

	/** 初始化函数，在设置完参数后，执行{@link #processImage(String, List)}前执行 */
	public void initEngine() {
		service = new ImageProcessService(template, timeout, poolSize);
	}

	/**
	 * 处理图片，根据图片多少决定是否使用多线程压缩
	 * 
	 * @param filePath
	 *            图片操作时存储图片的本地目录
	 * @param tasks
	 *            图片处理任务队列
	 */
	public <E extends ImageProcessResult> List<E> processImage(String filePath, List<? extends ImageProcessTask> tasks) {
		Assert.notEmpty(tasks, "task list cannot be empty");
		if (tasks.size() <= useMultiThreadMinSize) {// 当任务队列较小时使用单线程压缩
			List<E> results = new ArrayList<E>();
			for (ImageProcessTask task : tasks) {
				E result = processSingleImage(filePath, task);
				results.add(result);
			}
			return results;
		} else {
			return service.execute(filePath, tasks);
		}
	}

	/**
	 * 单张图片处理
	 * 
	 * @param filePath
	 *            图片操作时存储图片的本地目录
	 * @param task
	 *            图片处理任务
	 */
	@SuppressWarnings("unchecked")
	public <E extends ImageProcessResult, T extends ImageProcessTask> E processSingleImage(String filePath, T task) {
		try {
			return template.processImage(filePath, task);
		} catch (IOException e) {
			logger.warn("process image failed", e);
			E result = (E) new ImageProcessResult(ResultState.UNKOWN_FAILED);
			result.setOriginalFilename(task.getFilename());
			return result;
		}
	}

}